package com.vdisk4j;

import java.io.File;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.nutz.http.Http;
import org.nutz.http.Request;
import org.nutz.http.Request.METHOD;
import org.nutz.http.sender.FilePostSender;
import org.nutz.json.Json;
import org.nutz.lang.Encoding;

import com.vdisk4j.bean.VDiskResponse;

/**
 * <p/>本API实现了 http://vdisk.me/api/doc 描述的调用
 * <p/><b>创建实例后,必须先调用get_token方法进行授权!!否则其他方法均无法使用!!</b>
 * <p/>
 * <p/>
 * <p/>
 * <p/>
 * <p/>如果发现任何bug或有任何意见建议,请发送邮件到 vdisk4j@wendal.net
 * <p/>项目主页: http://vdisk4j.googlecode.com
 * <p/>
 * <p/>我的博客: http://wendal.net
 * @author wendal(vdisk4j@wendal.net)
 */
public class VDiskAPI {

	private String token;

	private long dologid;

	/**
	 * 保持同步
	 * @return
	 */
	public VDiskResponse keep() {
		return call("?a=keep", mw().map());
	}

	/**
	 * 获得token
	 * <p/><b>本方法是其他方法的基础,必须在其他方法被调用之前调用!!</b>
	 * <p/><b>本方法相当于登陆!!!</b>
	 * @param account 账号
	 * @param password 密码
	 * @param appkey 您的appkey
	 * @param appsecret 您的appsecret
	 * @param app_type 账号类型,如果为新浪微博账号,则为sinat,否则为null
	 * @return
	 */
	public VDiskResponse getToken(String account, String password,
			String appkey, String appsecret, String app_type) {
		try {
			SecretKeySpec spec = new SecretKeySpec(appsecret.getBytes("UTF-8"),
					"HmacSHA256");
			Mac mac = Mac.getInstance("HmacSHA256");
			mac.init(spec);
			long time = System.currentTimeMillis();
			String s = String.format(
					"account=%s&appkey=%s&password=%s&time=%s", account,
					appkey, password, time);
			byte[] data = mac.doFinal(s.getBytes("iso8859-1"));
			MapWrapper mw = MapWrapper.make();
			mw.put("account", account).put("password", password);
			mw.put("appkey", appkey).put("time", time);
			mw.put("signature", VDiskHelper.getHexString(data));
			if (app_type != null)
				mw.put("app_type", app_type);
			VDiskResponse re = call("?m=auth&a=get_token", mw.map());
			if(re != null && re.getErr_code() == VDiskConstant.Success)
				token = re.getData().get("token").toString();
			return re;
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 保持token,以避免token失效
	 * @return
	 */
	public VDiskResponse keepToken() {
		return call("?m=user&a=keep_token", mw().map());
	}

	/**
	 * 文件上传(10M以下)
	 * @param dir_id 目录的id,如果为0则表示跟目录
	 * @param file 需要上传的文件
	 * @param cover 重名时是否覆盖
	 * @return
	 */
	public VDiskResponse uploadFile(long dir_id, File file, boolean cover) {
		MapWrapper mw = mw().put("file", file);
		if(cover)
			mw.put("cover", "yes");
		else
			mw.put("cover", "no");
		return put("?m=file&a=upload_file", mw.map());
	}

	/**
	 * 上传文件并分享(10M以下)
	 * @param dir_id 目录的id,如果为0则表示跟目录
	 * @param file 需要上传的文件
	 * @param cover 重名时是否覆盖
	 * @return
	 */
	public VDiskResponse uploadShareFile(long dir_id, File file, boolean cover) {
		MapWrapper mw = mw().put("file", file);
		if(cover)
			mw.put("cover", "yes");
		else
			mw.put("cover", "no");
		return put("?m=file&a=upload_share_file", mw.map());
	}

	
	/**
	 * 创建目录
	 * @param create_name 目录的名称
	 * @param parent_id 父目录的id, 如果是根目录值为: 0
	 * @return
	 */
	public VDiskResponse createDir(String create_name, long parent_id) {
		MapWrapper mw = mw().put("create_name", create_name).put("parent_id", parent_id);
		return call("?m=dir&a=create_dir", mw.map());
	}

	/**
	 * 获得列表
	 * @param dir_id 目录id, 如果是根目录值为: 0
	 * @param page 当前页码,以1开始
	 * @param pageSize 每页条数,最小为2
	 * @return
	 */
	public VDiskResponse getList(long dir_id, int page, int pageSize) {
		if(page < 1)
			page = 1;
		if(pageSize < 2)
			pageSize = 2;
		MapWrapper mw = MapWrapper.make().put("token", token)
				// .put("dologid", dologid)
				.put("dir_id", dir_id).put("page", page)
				.put("parent_id", pageSize);
		return call("?m=dir&a=getlist", mw.map());
	}

	/**
	 * 获得容量信息
	 * @return
	 */
	public VDiskResponse getQuota() {
		return call("?m=file&a=get_quota", mw().map());
	}

	/**
	 * 无文件上传(sha1)
	 * @param dir_id 目录id, 根目录值为: 0
	 * @param sha1 文件的sha1值
	 * @param file_name 文件名
	 * @return
	 */
	public VDiskResponse uploadWithSha1(long dir_id, String sha1,
			String file_name) {
		MapWrapper mw = mw().put("dir_id", dir_id).put("sha1", sha1).put("file_name", file_name);
		return call("?m=file&a=upload_with_sha1", mw.map());
	}

	/**
	 * 获得单个文件信息
	 * @param fid 文件id
	 * @return
	 */
	public VDiskResponse getFileInfo(long fid) {
		MapWrapper mw = mw().put("fid", fid);
		return call("m=file&a=get_file_info", mw.map());
	}

	/**
	 * 删除目录
	 * @param dir_id 目录id (不能为0)
	 * @return
	 */
	public VDiskResponse deleteDir(long dir_id) {
		MapWrapper mw = mw().put("dir_id", dir_id);
		return call("?m=dir&a=delete_dir", mw.map());
	}

	/**
	 * 删除文件
	 * @param fid 文件id
	 * @return
	 */
	public VDiskResponse deleteFile(long fid) {
		MapWrapper mw = mw().put("fid", fid);
		return call("?m=file&a=delete_file", mw.map());
	}

	/**
	 * 复制文件
	 * @param fid 文件id
	 * @param new_name 副本的名称
	 * @param to_dir_id 目标目录的id, 根目录值为: 0
	 * @return
	 */
	public VDiskResponse copyFile(long fid, String new_name, long to_dir_id) {
		MapWrapper mw = mw().put("fid", fid).put("new_name", new_name)
				.put("to_dir_id", to_dir_id);
		return call("?m=file&a=copy_file", mw.map());
	}

	/**
	 * 移动文件
	 * @param fid 文件id
	 * @param new_name 移动后的文件名
	 * @param to_dir_id 目标目录的id, 根目录值为: 0
	 * @return
	 */
	public VDiskResponse moveFile(long fid, String new_name, long to_dir_id) {
		MapWrapper mw = mw().put("fid", fid).put("new_name", new_name)
				.put("to_dir_id", to_dir_id);
		return call("?m=file&a=move_file", mw.map());
	}

	/**
	 * 文件重命名
	 * @param fid 文件id
	 * @param new_name 新文件名
	 * @return
	 */
	public VDiskResponse renameFile(long fid, String new_name) {
		MapWrapper mw = mw().put("fid", fid).put("new_name", new_name);
		return call("?m=file&a=rename_file", mw.map());
	}

	/**
	 * 目录重命名 
	 * @param dir_id 目录id(不能为0)
	 * @param new_name 新名称
	 * @return
	 */
	public VDiskResponse renameDir(long dir_id, String new_name) {
		MapWrapper mw = mw().put("new_name", new_name)
				.put("dir_id", dir_id);
		return call("?m=file&a=rename_file", mw.map());
	}

	/**
	 * 移动目录
	 * @param dir_id 目录id(不能为0)
	 * @param new_name 新名称
	 * @param to_parent_id 目标父目录id, 根目录值为: 0
	 * @return
	 */
	public VDiskResponse moveDir(long dir_id, String new_name,
			long to_parent_id) {
		MapWrapper mw = mw().put("to_parent_id", to_parent_id).put("new_name", new_name)
				.put("dir_id", dir_id);
		return call("?m=file&a=move_dir", mw.map());
	}

	/**
	 * 分享文件
	 * @param fid 文件id
	 * @return
	 */
	public VDiskResponse shareFile(long fid) {
		MapWrapper mw = mw().put("fid", fid);
		return call("?m=file&a=share_file", mw.map());
	}

	/**
	 * 取消分享
	 * @param fid 文件id
	 * @return
	 */
	public VDiskResponse cancelShareFile(long fid) {
		MapWrapper mw = mw().put("fid", fid);
		return call("?m=file&a=cancel_share_file", mw.map());
	}

	/**
	 * 获得回收站列表
	 * @param page 第几页
	 * @param pageSize 每页显示条数
	 * @return
	 */
	public VDiskResponse getRecycleList(int page, int pageSize) {
		if(page < 1)
			page = 1;
		if(pageSize < 2)
			pageSize = 2;
		MapWrapper mw = mw().put("page", page).put("pagesize", pageSize);
		return call("?m=recycle&a=get_list", mw.map());
	}

	/**
	 * 清空回收站
	 * @return
	 */
	public VDiskResponse truncateRecycle() {
		return call("?m=file&a=truncate_recycle", mw().map());
	}

	/**
	 * 从回收站中彻底删除一个文件
	 * @param fid 要删除的文件id
	 * @return
	 */
	public VDiskResponse deleteRecycleFile(long fid) {
		MapWrapper mw = mw().put("fid", fid);
		return call("?m=recycle&a=delete_file", mw.map());
	}

	/**
	 * 从回收站中彻底删除一个目录
	 * @param dir_id 要删除的目录id
	 * @return
	 */
	public VDiskResponse deleteRecycleDir(long dir_id) {
		MapWrapper mw = mw().put("dir_id", dir_id);
		return call("?m=recycle&a=delete_dir", mw.map());
	}

	/**
	 * 从回收站中还原一个文件
	 * @param fid 要还原的文件id
	 * @return
	 */
	public VDiskResponse restoreRecycleFile(long fid) {
		MapWrapper mw = mw().put("fid", fid);
		return call("?m=recycle&a=restore_file", mw.map());
	}

	/**
	 * 从回收站中还原一个目录
	 * @param dir_id 要还原的目录id
	 * @return
	 */
	public VDiskResponse restoreRecycleDir(long dir_id) {
		MapWrapper mw = mw().put("dir_id", dir_id);
		return call("?m=recycle&a=restore_dir", mw.map());
	}

	/**
	 * 通过路径得到目录id
	 * @param path 路径
	 * @return
	 */
	public VDiskResponse getDiridWithPath(String path) {
		MapWrapper mw = mw().put("path", path);
		return call("?m=recycle&a=get_dirid_with_path", mw.map());
	}

	protected VDiskResponse call(String url, Map<String, Object> parms) {
		String resp = Http.post(VDiskConstant.SERVER + url, parms,
				Encoding.UTF8, Encoding.UTF8);
		if (resp == null)
			return null;// TODO 抛出异常
		VDiskResponse re = Json.fromJson(VDiskResponse.class, resp);
		if(re.getErr_code() == VDiskConstant.Success) {
			dologid = re.getDologid();
		}
		return re;
	}

	protected VDiskResponse put(String url, Map<String, Object> parms) {
		FilePostSender sender = new FilePostSender(Request.create(
				VDiskConstant.SERVER + url, METHOD.POST, parms));
		String resp = sender.send().getContent();
		if (resp == null)
			return null;// TODO 抛出异常
		VDiskResponse re = Json.fromJson(VDiskResponse.class, resp);
		if(re.getErr_code() == VDiskConstant.Success) {
			//需要先判断是否存在dolog_dir, thanks "木子开泰"
			if(re.getDologdir() == null || re.getDologdir().length == 0)
				dologid = re.getDologid();
		}
		return re;
	}
	
	protected MapWrapper mw() {
		return MapWrapper.make().put("token", token).put("dologid", dologid);
	}
}
